package org.reos;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * Created with IntelliJ IDEA.
 * User: Alexander Rogin
 * Date: 25.12.13
 * Time: 14:14
 * To change this template use File | Settings | File Templates.
 */
public class ReSerial {
    private static final int SERIAL_BAUDRATE = 115200;
    private static final int SERIAL_DATABITS = SerialPort.DATABITS_8;
    private static final int SERIAL_STOPBITS = SerialPort.STOPBITS_1;
    private static final int SERIAL_PARITY = SerialPort.PARITY_NONE;

    private String portName;
    private InputStream in;
    private OutputStream out;
    SerialPort serialPort;

    public ReSerial(String portName) {
        this.portName = portName;
    }

    public void connect() throws Exception
    {
        CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
        if (portIdentifier.isCurrentlyOwned())
        {
            System.out.println("Error: Port is currently in use");
        }
        else
        {
            // TODO Find out what this number means
            CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000);

            if (commPort instanceof SerialPort)
            {
                serialPort = (SerialPort) commPort;
                serialPort.setSerialPortParams(SERIAL_BAUDRATE, SERIAL_DATABITS, SERIAL_STOPBITS, SERIAL_PARITY);

                in = serialPort.getInputStream();
                //OutputStream out = serialPort.getOutputStream();  // no need to write

                //(new Thread(new SerialReader(in, sharedRxBuffer))).start();
                //(new Thread(new SerialWriter(out))).start();      // no need to write
                System.out.println("Serial port opened.");
            }
            else
            {
                System.out.println("Error: Only serial ports are handled.");
            }
        }
    }

    public Byte readByteIfAvailable() {
        byte[] buffer = new byte[1];
        int len = -1;
        try
        {
            len = this.in.read(buffer);
            if (len > 0) {
                return buffer[0];
            }
        }
        catch ( IOException e )
        {
            e.printStackTrace();
        }
        return null;
    }

    public void closeConnection() {
        try {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        serialPort.close();
    }

    /** */
    public static class SerialReader implements Runnable
    {
        private InputStream in;
        private ArrayBlockingQueue<Byte> sharedRxBuffer;

        public SerialReader(InputStream in, ArrayBlockingQueue<Byte> sharedRxBuffer)
        {
            this.in = in;
            this.sharedRxBuffer = sharedRxBuffer;
        }

        public void run ()
        {
            //byte[] buffer = new byte[1024];
            byte[] buffer = new byte[1];
            int len = -1;
            try
            {
                //while ((len = this.in.read(buffer)) > -1)
                while ((len = this.in.read(buffer, 0, 1)) > -1)
                {
                    // TODO: Handle incoming data
                    System.out.print("Read from serial: " + buffer[0]);
                    System.out.print(new String(buffer, 0, len));
                    if (sharedRxBuffer.offer(buffer[0]) == false) {
                        System.out.println("RX queue is full, byte dropped");
                    }
                }
            }
            catch ( IOException e )
            {
                e.printStackTrace();
            }
        }
    }

    /** */
    public static class SerialWriter implements Runnable
    {
        OutputStream out;

        public SerialWriter ( OutputStream out )
        {
            this.out = out;
        }

        public void run ()
        {
            try
            {
                int c = 0;
                while ( ( c = System.in.read()) > -1 )
                {
                    this.out.write(c);
                }
            }
            catch ( IOException e )
            {
                e.printStackTrace();
            }
        }
    }
}
